package basicGramer

import (
	"fmt"
	"sync"
	"time"
)

/**
  并发编程遇到的一些demo
*/

func init() {
	fmt.Println("\n\n============这里是并发编程中的init()函数部分\n")
	threadWait()
	LockMutex()   //  互斥锁
	LockRWMutex() //  读写锁
}

// 互斥锁
func LockMutex() {
	var wg sync.WaitGroup
	lock := &sync.Mutex{} // & 表示获取到 sync.Mutex的指针地址
	count := 0
	wg.Add(3)
	go add(&count, &wg, lock)
	go add(&count, &wg, lock)
	go add(&count, &wg, lock)
	wg.Wait()
	fmt.Println("count 的值为：", count)
}

// 用指针地址地址接受。
func add(count *int, wg *sync.WaitGroup, lock *sync.Mutex) {
	for i := 0; i < 100; i++ {
		lock.Lock()
		*count = *count + 1
		lock.Unlock()
	}
	wg.Done() // 表示结束该协程
}

// 读写锁
func LockRWMutex() {
	lock := &sync.RWMutex{} // 读写锁的定义、必须是要用指针的形式去操作。
	lock.Lock()             //开始写锁，后边的程序都会在写锁释放的时候，才会进行
	for i := 0; i < 4; i++ {

		go func(i int) {
			fmt.Printf("协程%d读锁开启\n", i)
			lock.RLock() //开始读锁
			fmt.Printf("第 %d 个协程获得读锁, sleep 1s 后，释放锁\n", i)
			time.Sleep(time.Second * 1)
			lock.RUnlock()
		}(i)
	}
	time.Sleep(time.Second * 2)
	fmt.Println("准备释放写锁，读锁不再阻塞") // 同时读锁获取到资源，开始执行任务
	lock.Unlock()

	lock.Lock()
	fmt.Println("执行完毕")
	lock.Unlock()
}

/*
  线程等待的操作实现
  FIXME:  defer、Add 、Wait实现
    Add：初始值为0，你传入的值会往计数器上加，这里直接传入你子协程的数量
    Done：当某个子协程完成后，可调用此方法，会从计数器上减一，通常可以使用 defer 来调用。
    Wait：阻塞当前协程，直到实例里的计数器归零。
*/
func threadWait() {
	var wait sync.WaitGroup
	wait.Add(2)
	go workForSyncWait(1, &wait)
	go workForSyncWait(2, &wait)
	wait.Wait()
}

func workForSyncWait(x int, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 5; i++ {
		fmt.Printf(" worker工作者 %d = %d\n", x, i)
	}
}
